package projectmanagement

import (
	"errors"
	"playbook/ginsvr/src/global"
	"playbook/ginsvr/src/orm"
	"playbook/ginsvr/src/source/gene/tpl"
	"playbook/ginsvr/src/utils/fileutil"
	"playbook/ginsvr/src/utils/uuidutil"
	"strings"
	"text/template"

	"github.com/sirupsen/logrus"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var db *gorm.DB
var err error
var funcMap template.FuncMap

func init() {
	db, err = gorm.Open(sqlite.Open("playbook.db"), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})
}

type FullProject struct {
	Project Project `json:"project"`
}

type Project struct {
	Projectid   string `json:"id"`
	Projectname string `json:"projectname"`
	Projectdesc string `json:"projectdesc"`
	Createuser  string `json:"createuser"`
	Projectpath string `json:"projectpath"`
}

type ProjectModel struct {
	ProjectName        string
	PackageName        string
	ProjectApplication string
}

// 项目创建相关方法
func AddProject(fullProject FullProject) (orm.Response, error) {
	var resp orm.Response
	project := fullProject.Project
	if project.Projectpath == "" {
		resp.RespCode = "000002"
		resp.RespMsg = "projectpath can not be null!"
		return resp, errors.New("projectpath can not be null!")
	}
	if project.Projectname == "" {
		resp.RespCode = "000003"
		resp.RespMsg = "projectname can not be null!"
		return resp, errors.New("projectname can not be null!")
	}
	// 项目唯一性校验
	var count int64
	db.Table("project").Where("projectname = ?", project.Projectname).Count(&count)
	if count > 0 {
		resp.RespCode = "000001"
		resp.RespMsg = "project already exist"
		return resp, errors.New("project already exist")
	}
	_, errTemp := MakerProjectTemp(project)
	if errTemp != nil {
		resp.RespCode = "000001"
		resp.RespMsg = "create dir failed"
		return resp, errors.New("create dir failed")
	}
	projectid := project.Projectid
	if projectid == "" {
		projectid = uuidutil.GetUUID()
	}

	err := db.Table("project").CreateInBatches([]map[string]interface{}{{
		"projectid":   projectid,
		"projectname": project.Projectname,
		"createuser":  project.Createuser,
		"projectdesc": project.Projectdesc,
		"projectpath": project.Projectpath,
	}}, 1)
	if err.Error != nil {
		global.LOG.WithFields(logrus.Fields{
			"err":       err,
			"projectid": projectid,
		}).Error("create project err.")
		resp.RespCode = "000005"
		resp.RespMsg = err.Error.Error()
		return resp, nil
	}
	resp.RespCode = "000000"
	resp.RespMsg = projectid
	return resp, nil
}

// 项目更新相关方法
func UpdateProject(fullProject FullProject) (orm.Response, error) {
	var resp orm.Response
	project := fullProject.Project
	var originproject Project
	db.Table("project").Where("projectid = ?", project.Projectid).Find(&originproject)
	// 通过项目id校验项目是否存在
	if originproject == (Project{}) {
		resp.RespCode = "000001"
		resp.RespMsg = "project does not exist"
		return resp, errors.New("project does not exist")
	}
	// 项目唯一性校验
	if project.Projectname != originproject.Projectname {
		var count int64
		db.Table("project").Where("projectname = ?", project.Projectname).Count(&count)
		if count > 0 {
			resp.RespCode = "000001"
			resp.RespMsg = "project already exist"
			return resp, errors.New("project already exist")
		}
	}

	// 复制项目文件到新的项目目录下
	var sourcePath string
	localpath := orm.GetLocalPath(global.USER)
	if fileutil.SepTransform(originproject.Projectpath) == global.PTHSEP {
		sourcePath = localpath.LocalPath + global.PTHSEP + global.PROGRAM + originproject.Projectname
	} else if strings.HasPrefix(fileutil.SepTransform(originproject.Projectpath), global.PTHSEP) {
		sourcePath = localpath.LocalPath + originproject.Projectpath + global.PTHSEP + global.PROGRAM + originproject.Projectname
	} else {
		sourcePath = localpath.LocalPath + global.PTHSEP + originproject.Projectpath + global.PTHSEP + global.PROGRAM + originproject.Projectname
	}
	targetPath := localpath.LocalPath + global.PTHSEP + project.Projectpath + global.PTHSEP + global.PROGRAM + project.Projectname

	// 如果项目路径未发生改变，不做文件的处理
	if originproject.Projectpath != project.Projectpath {
		errs := fileutil.CopyDir(sourcePath, targetPath)
		if errs != nil {
			resp.RespCode = "000002"
			resp.RespMsg = errs.Error()
			return resp, errs
		}

		// 删除旧项目路径下的文件
		err := fileutil.DeleteFile(sourcePath, true)
		if err != nil {
			resp.RespCode = "000003"
			resp.RespMsg = "remove project file err"
			return resp, err
		}
	}
	// 更新有变化的属性
	err := db.Table("project").Where("projectid=?  ", project.Projectid).Updates(project)
	if err.Error != nil {
		global.LOG.WithFields(logrus.Fields{
			"err":       err,
			"projectid": project.Projectid,
		}).Error("update project err.")
		resp.RespCode = "000004"
		resp.RespMsg = err.Error.Error()
		return resp, errors.New(err.Error.Error())
	}
	resp.RespCode = "000000"
	resp.RespMsg = "project update success!"

	return resp, nil
}

// 通过项目id查询项目路径
func GetProjectPathById(projectid string) interface{} {
	var dataMap = make(map[string]interface{})
	var count int64
	db.Table("project").Where("projectid = ?", projectid).Count(&count)
	if count == 0 {
		dataMap["respCode"] = "000001"
		dataMap["respMsg"] = "project not found"
		return dataMap
	}
	var projectList []Project
	db.Table("project").Where("projectid = ?", projectid).Find(&projectList)
	dataMap["respCode"] = "000000"
	dataMap["projectpath"] = projectList[0].Projectpath
	dataMap["projectname"] = projectList[0].Projectname
	return dataMap
}

// 通过项目id和标识查询项目路径
func GetProjectPathByIdFlag(projectid string, flag string) interface{} {
	var dataMap = make(map[string]interface{})
	pro := GetProjectPathById(projectid).(map[string]interface{})
	if pro["respCode"] != "000000" {
		return pro
	}
	if pro["projectpath"] == "" || pro["projectname"] == "" {
		dataMap["respCode"] = "000002"
		dataMap["respMsg"] = "projectpath or projectname is null"
		return dataMap
	}
	projectPath := pro["projectpath"].(string)
	projectName := pro["projectname"].(string)
	projectNameFlag := global.PROGRAM + projectName
	dataMap["respCode"] = pro["respCode"]
	dataMap["projectpath"] = fileutil.SepTransform(projectPath) + global.PTHSEP + projectNameFlag + global.PTHSEP + projectNameFlag + "-" + flag
	return dataMap
}

// 项目列表查询
func GetProjectList(projectname string, page int, pagesize int) interface{} {
	var total int64
	db.Table("project").Where("projectname like ?", projectname+"%").Count(&total)
	var projectList []Project
	db.Table("project").Where("projectname like ?", projectname+"%").Limit(pagesize).Offset((page - 1) * pagesize).Find(&projectList)
	var dataMap = make(map[string]interface{})
	dataMap["total"] = total
	dataMap["data"] = projectList
	return dataMap
}

// 查询服务端项目列表信息
func GetServerProjectList() ([]Project, error) {
	var projectList []Project
	err := db.Table("project").Find(&projectList).Error
	if err != nil {
		return projectList, err
	}
	return projectList, nil
}

// 查询服务端项目列表信息
func UpdateLocalDateFromServer(projectList []Project) (orm.Response, error) {
	var resp orm.Response
	var projectid string
	for _, project := range projectList {
		projectid = project.Projectid
		var total int64
		db.Table("project").Where("projectid = ?", projectid).Count(&total)
		if total > 0 {
			err := db.Table("project").Where("projectid=? ", project.Projectid).Updates(project).Error
			if err != nil {
				resp.RespCode = "000001"
				resp.RespMsg = "Synchronization failed"
				return resp, errors.New("Synchronization failed")
			}
		} else if total == 0 {
			err := db.Table("project").CreateInBatches([]map[string]interface{}{{
				"projectid":   project.Projectid,
				"projectname": project.Projectname,
				"createuser":  project.Createuser,
				"projectdesc": project.Projectdesc,
				"projectpath": project.Projectpath,
			}}, 1).Error
			if err != nil {
				resp.RespCode = "000001"
				resp.RespMsg = "Synchronization failed"
				return resp, errors.New("Synchronization failed")
			}
		}
		_, err := MakerProjectTemp(project)
		if err != nil {
			resp.RespCode = "000002"
			resp.RespMsg = "dir creat err"
			return resp, err
		}
	}
	resp.RespCode = "000000"
	resp.RespMsg = "Synchronization Succeeded"
	return resp, nil
}

func MakerProjectTemp(project Project) (resp orm.Response, err error) {
	// 创建本地文件夹
	scriptSrcPath := orm.GetGeneSrcDefine("script").Srcpath
	coreSrcPath := orm.GetGeneSrcDefine("core").Srcpath
	bootJsonPath := orm.GetGeneSrcDefine("composejson").Srcpath
	var projectDate ProjectModel
	projectDate.ProjectName = project.Projectname
	projectDate.PackageName = "com.psbc.cbcbp." + project.Projectname
	ProjectName := project.Projectname
	projectDate.ProjectApplication = strings.ToUpper(string(ProjectName[0])) + ProjectName[1:]
	// 根pom文件生成
	rootPath := project.Projectpath + global.PTHSEP + global.PROGRAM + ProjectName
	tmplName := tpl.Tplpom
	standardName := "pom.xml"
	if !fileutil.FileExist(rootPath+global.PTHSEP+standardName, false) {
		_, err := MakerProjectTmplDir(rootPath, tmplName, standardName, projectDate)
		if err != nil {
			return resp, err
		}
	}

	// -boot的pom文件生成
	tmplBootName := tpl.Tplbootpom
	bootPath := project.Projectpath + global.PTHSEP + global.PROGRAM + ProjectName + global.PTHSEP + global.PROGRAM + ProjectName + "-boot"
	if !fileutil.FileExist(bootPath+global.PTHSEP+standardName, false) {
		_, err := MakerProjectTmplDir(bootPath, tmplBootName, standardName, projectDate)
		if err != nil {
			return resp, err
		}
	}

	// -boot的json目录生成
	errBoot := fileutil.MakeDirProject(bootPath + global.PTHSEP + bootJsonPath)
	if errBoot != nil {
		return resp, errBoot
	}

	// -boot的启动类生成
	tmplApplicationName := tpl.Tplapplication
	standardNameApplication := strings.ToUpper(string(ProjectName[0])) + ProjectName[1:] + "Application.java"
	applicationPath := bootPath + global.PTHSEP + coreSrcPath + global.PTHSEP + project.Projectname
	if !fileutil.FileExist(applicationPath+global.PTHSEP+standardNameApplication, false) {
		_, err := MakerProjectTmplDir(applicationPath, tmplApplicationName, standardNameApplication, projectDate)
		if err != nil {
			return resp, err
		}
	}

	// -core的pom文件生成
	corePath := project.Projectpath + global.PTHSEP + global.PROGRAM + ProjectName + global.PTHSEP + global.PROGRAM + ProjectName + "-core"
	tmplCoreName := tpl.Tplcorepom
	if !fileutil.FileExist(corePath+global.PTHSEP+standardName, false) {
		_, err := MakerProjectTmplDir(corePath, tmplCoreName, standardName, projectDate)
		if err != nil {
			return resp, err
		}
	}
	// -core的src生成
	errCore := fileutil.MakeDirProject(corePath + global.PTHSEP + coreSrcPath + global.PTHSEP + ProjectName)
	if errCore != nil {
		return resp, errCore
	}

	// -script的pom生成
	scriptPath := project.Projectpath + global.PTHSEP + global.PROGRAM + ProjectName + global.PTHSEP + global.PROGRAM + ProjectName + "-script"
	tmplScriptName := tpl.Tplscriptpom
	if !fileutil.FileExist(scriptPath+global.PTHSEP+standardName, false) {
		_, err := MakerProjectTmplDir(scriptPath, tmplScriptName, standardName, projectDate)
		if err != nil {
			return resp, err
		}
	}
	// -script的src生成
	errScript := fileutil.MakeDirProject(scriptPath + global.PTHSEP + scriptSrcPath)
	if errScript != nil {
		return resp, errScript
	}
	return resp, nil
}

func MakerProjectTmplDir(path string, tmplName string, standerName string, projectDate ProjectModel) (resp orm.Response, err error) {
	file := fileutil.GetClearFile(path, standerName)
	tmpl, errTmp := template.New(standerName).Funcs(funcMap).Parse(tmplName)
	if errTmp != nil {
		return resp, errTmp
	}
	err = tmpl.Execute(file, projectDate)
	if err != nil {
		return resp, err
	}
	return resp, nil
}
